package hnx.ca.security;

import hnx.ca.util.ErrorCodes;
import hnx.ca.util.GenEnveloped;
import hnx.ca.util.RootConfig;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.security.Key;
import java.security.KeyPair;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.util.Enumeration;
import java.util.Properties;

import org.apache.commons.lang3.StringUtils;

public class XmlSigner {
	public static Properties props = new Properties();
	private static KeyPair keyPair;
	private static PrivateKey privateKey;
	protected static int errorCode;
	protected static Certificate[] certChain;
	public static String certPassword;
	public static int signXmlFile(String inputFile, String outputFile){
		errorCode = ErrorCodes.SIGN_XML.SUCCESS;
		try {
			initKeyPair();
			String fileType = StringUtils.substringAfterLast(inputFile, ".");
			
			if(!fileType.equalsIgnoreCase("xml")){
				return ErrorCodes.SIGN_XML.INVALID_INPUT_FILE_TYPE;
			}
			
			if (inputFile != null && outputFile != null && privateKey != null && certChain != null) {
				GenEnveloped.sign_xml(inputFile, outputFile, privateKey, certChain);
			}else{
				if(StringUtils.isEmpty(outputFile)){
					errorCode = ErrorCodes.SIGN_XML.INVALID_OUTPUT_FILE;
				}
				return errorCode;
			}
		}catch (Exception e){
			System.out.println("[Exception] " + e.getMessage());
			errorCode = ErrorCodes.SIGN_XML.OTHER_EXCEPTION;
		}
		
		return errorCode;
	}
	
	public static String getOutputFileName(String inputFileName){
		String fileName = StringUtils.substringBeforeLast(inputFileName, ".");
		return fileName + "_signed.xml";
	}
	
	public static KeyPair getPrivateKey(KeyStore keystore, String alias, char[] password) {
        try {
            Key key = keystore.getKey(alias, password);
            if (key instanceof PrivateKey) {
                Certificate cert = keystore.getCertificate(alias);
                PublicKey publicKey = cert.getPublicKey();
                return new KeyPair(publicKey, (PrivateKey) key);
            }
        }catch(Exception e){
        	System.out.println("[Exception]" + e.getMessage());
        	errorCode = ErrorCodes.SIGN_XML.GET_KEY_PAIR_EXCEPTION;
        }
        return null;
    }
	
	@SuppressWarnings({ "unused", "rawtypes" })
	public static void initKeyPair() throws KeyStoreException, NoSuchProviderException, IOException, NoSuchAlgorithmException, CertificateException, UnrecoverableKeyException {
		loadProperties();
		KeyStore keyStore = KeyStore.getInstance("Windows-MY", "SunMSCAPI" );
        keyStore.load(null, null);
        if (keyStore == null) {
        	errorCode = ErrorCodes.SIGN_XML.GET_KEY_STORE_EXCEPTION;
        }
        Enumeration enumeration = keyStore.aliases();
        while (enumeration.hasMoreElements()) {
            String alias = enumeration.nextElement().toString();
            //System.out.println("" + alias);
            keyStore.getCertificateChain(alias);
            certChain = keyStore.getCertificateChain(alias);
            keyPair = getPrivateKey(keyStore, alias, certPassword.toCharArray());
            if (keyPair != null) {
                privateKey = keyPair.getPrivate();
            }            
        }
    }
	
	public static void main(String args[]){
		int result = signXmlFile("D:\\test.xml", "D:\\test_sign1.xml");
		System.out.println(result);
	}
	
	public static void loadProperties(){
		String fileName = RootConfig.shareInstance().getRoot() + "config/database.conf";	
		try {
			props.load(new FileInputStream(fileName));
		} catch (Exception e) {
			e.printStackTrace();
			certPassword = "12345";
		}  
		certPassword = props.getProperty("certPassword", certPassword);
	}
	
}
